// index.js
// This is the main entry point of our application
const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const depthLimit = require('graphql-depth-limit');
const { createComplexityLimitRule } = require("graphql-validation-complexity");


// 在本地开发时需要使用环境变量 上线部署之后 需要注释掉
// https://cloud.tencent.com/developer/ask/sof/1380524
require('dotenv').config();

const db = require("./db");
const models = require("./models");
const typeDefs = require("./schema");
// 为模式字段提供解析函数
const resolvers = require("./resolvers");

const jwt = require("jsonwebtoken");
// 通过JWT获取用户信息
const getUser = token => {
  if (token) {
    try {
      // 返回通过令牌获取的用户信息
      return jwt.verify(token, process.env.JWT_SECRET);
    } catch (err) {
      // 如果令牌有问题，抛出错误
      throw new Error("Session invalid");
    }
  }
}

// 在 .env 文件指定的端口或4000端口上运行服务器
const port = process.env.PORT || 4000;
// 把DB_HOST值存入一个变量
const DB_HOST = process.env.DB_HOST;
// 让我们的应用免受常见的web漏洞攻击
const helmet = require("helmet");
// 跨域资源共享
const cors = require("cors");

const app = new express();
app.use(helmet());
app.use(cors());

// 连接数据库
db.connect(DB_HOST);

// 设置Apollo Server
const server = new ApolloServer({ 
  typeDefs, 
  resolvers,
  validationRules: [depthLimit(5), createComplexityLimitRule(1000)],
  context: ({ req }) => {
    // 从请求头中获取令牌
    const token = req.headers.authorization;
    // 尝试使用令牌检索用户
    const user = getUser(token);
    // 暂且把用户输出到控制台中
    console.log(user);
    // 把数据库模型添加到上下文中
    return { models, user };
  }
});

// 应用 Apollo Graphql 中间件，把路径设为 /api
server.applyMiddleware({ app, path: '/api' });

app.listen({ port }, () =>
  console.log(
    `GraphQL Server running at http://localhost:${port}${server.graphqlPath}`
  )
);
